package com.song.demo.webmvc.servlet;

import com.song.demo.webmvc.annotation.GPRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 原生Spring的HandlerAdapter主要完成请求传到服务端的参数列表与Method实参列表的对应关系，完成参数值的
 * 类型转换工作，核心方法是handle(),在handle()方法中用反射来调用被适配的目标方法
 * 并将转换好的参数列表传递过去
 */
public class GPHandlerAdapter {

    public boolean supports(Object handler){
        return (handler instanceof  GPHandlerMapping);

    }


    public GPModelAndView handle(HttpServletRequest req, HttpServletResponse resp, GPHandlerMapping handler) throws InvocationTargetException, IllegalAccessException {
        HashMap<String, Integer> paramMapping = new HashMap<>();

        //这里只是给出参数名
        Annotation[][] parameterAnnotations = handler.getMethod().getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            for (Annotation annotation : parameterAnnotations[i]) {
                if (annotation instanceof GPRequestParam){
                    String paramName = ((GPRequestParam) annotation).value();
                    if (!"".equals(paramName.trim())){
                        paramMapping.put(paramName,i);
                    }
                }
            }
        }

        // 1.准备形参列表
        Class<?>[] parameterTypes = handler.getMethod().getParameterTypes();
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> type = parameterTypes[i];
            if (type == HttpServletRequest.class || type == HttpServletResponse.class){
                paramMapping.put(type.getName(),i);
            }
        }
        //2.得到自定义命名参数所在的位置
        Map<String,String[]> parameterMap = req.getParameterMap();

        //3.构造实参类表
        Object[] paramValues = new Object[parameterTypes.length];

        for (Map.Entry<String, String[]> param : parameterMap.entrySet()) {
            String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll("\\s", "");
            if (!paramMapping.containsKey(param.getKey())){
                continue;
            }
            Integer index = paramMapping.get(param.getKey());
            paramValues[index] = caseStringValue(value,parameterTypes[index]);
        }
        if (paramMapping.containsKey(HttpServletRequest.class.getName())){
            Integer reqIndex = paramMapping.get(HttpServletRequest.class.getName());
            paramValues[reqIndex] = req;
        }
        if (paramMapping.containsKey(HttpServletResponse.class.getName())){
            Integer reqIndex = paramMapping.get(HttpServletResponse.class.getName());
            paramValues[reqIndex] = resp;
        }
        //4.从handler中取出Controller、Method,然后利用反射机制进行调用
        Object result = handler.getMethod().invoke(handler.getController(), paramValues);
        if (result == null){
            return null;
        }
        boolean isModelAndView = handler.getMethod().getReturnType() == GPModelAndView.class;
        if (isModelAndView){
            return (GPModelAndView)result;
        }else{
            return null;
        }
    }

    private Object caseStringValue(String value, Class<?> clazz) {
        if (clazz == String.class){
            return value;
        }else if (clazz == Integer.class){
            return Integer.valueOf(value);
        }else if (clazz == int.class){
            return Integer.valueOf(value).intValue();
        }else {
            return null;
        }
    }


}
